﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Galaktika.BI.Silverlight.ClientApp.Web.Runtime.DataAccess;
using Galaktika.BI.Runtime.Services;
using Galaktika.BI.Silverlight.Services;

namespace Galaktika.BI.Silverlight.ClientApp.Services
{
    internal class AnalysisObjectCache
    {
        public class SingleServerCache
        {
            public SingleServerCache(string connectionString)
            {
                this.ConnectionString = connectionString;
                m_Cache = new Dictionary<string, AnalysisObject>();
            }

            public string ConnectionString { get; private set; }

            Dictionary<string, AnalysisObject> m_Cache;
            public AnalysisObject this[string uniqueName, string cubeName, IBindingContext context]
            {
                get
                {
                    lock (m_Cache)
                    {
                        AnalysisObject ao;
                        m_Cache.TryGetValue(uniqueName, out ao);
                        if (ao == null)
                        {
                            ao = this.RetrieveObject(uniqueName, this.GetFramedCubeName(cubeName), context);
                        }

                        return ao;
                    }
                }
            }

            const string RETRIEVE_QUERY = @"select {0} on 0, {{}} on 1 from {1}";
            private AnalysisObject RetrieveObject(string uniqueName, string cubeName, IBindingContext context)
            {
                AnalysisObject ao = null;
                try
                {
                    var query = string.Format(RETRIEVE_QUERY, uniqueName, cubeName);
                    var res = OlapQueryExecutor.ExecuteQuery(this.ConnectionString, query, null, context);
                    if (res.ResultType != KnownContentTypes.Error && res.ResultType != KnownContentTypes.ADOMDError)
                    {
                        var cs = res.Data;
                        if (cs != null && cs.Axes.Count > 0)
                        {
                            foreach (var pos in cs.Axes[0].Positions)
                            {
                                foreach (var member in pos.Members)
                                {
                                    var m = cs.Axes[0].Members[member.Id];
                                    var tmp = this.Update(m.UniqueName, m);
                                    if (m.UniqueName == uniqueName)
                                    {
                                        ao = tmp;
                                    }
                                }
                            }
                        }
                    }
                }
                catch
                {
                    // miss
                }

                return ao;
            }

            private AnalysisObject Update(string uniqueName, object analysisObject)
            {
                AnalysisObject ao;
                m_Cache.TryGetValue(uniqueName, out ao);
                if (ao == null)
                {
                    ao = new AnalysisObject(analysisObject);
                    m_Cache.Add(uniqueName, ao);
                }
                else
                {
                    ao.SetObject(analysisObject);
                }

                return ao;
            }

            private string GetFramedCubeName(string cubeName)
            {
                if (cubeName.StartsWith("[", StringComparison.Ordinal))
                {
                    return cubeName;
                }

                return string.Format("[{0}]", cubeName);
            }
        }

        public AnalysisObjectCache()
        {
            m_Cache = new Dictionary<string, SingleServerCache>();
        }

        Dictionary<string, SingleServerCache> m_Cache;
        public SingleServerCache this[string connectionString]
        {
            get
            {
                lock (m_Cache)
                {
                    SingleServerCache cache;
                    m_Cache.TryGetValue(connectionString, out cache);
                    if (cache == null)
                    {
                        cache = new SingleServerCache(connectionString);
                        m_Cache.Add(connectionString, cache);
                    }

                    return cache;
                }
            }
        }
    }
}
